package com.fingard.diagnostics.trace;

import java.util.Date;

import com.fingard.FGBiz;
import com.fingard.constant.Format;
import com.fingard.diagnostics.LogHelper;
import com.fingard.text.StringHelper;

public class LogTrace implements Runnable {
	
	private LogTraceFilePath pathHelper;
	
	private LogQueue[] logQueueList;
	private int nowInIdx;
	
	
	public LogTrace(String p_defDir){
		pathHelper = new LogTraceFilePath(p_defDir);
		logQueueList = new LogQueue[3];
		for(int i=0;i<logQueueList.length;i++){
			logQueueList[i] = new LogQueue();
		}
		nowInIdx = 0;
	}
	
	/**增加日志目录配置，用于分目录写日志，初始时，添加了bank，即直联渠道日志目录*/
	public void addLogDir(String pKey,String pDir){
		pathHelper.addLogDir(pKey, pDir);
	}
	
	public void debug(String p_logCode, String... p_values){
		appendLog("debug","", p_logCode,"",true,1,null,p_values);
	}

	public void info(String p_logCode, String... p_values){
		appendLog("info","", p_logCode, "",true,1,null,p_values);
	}
	
	/**等级：info，用于输出直联渠道日志*/
	public void infoBank(String p_logCode,String pPrefix, String... p_values){
		appendLog("info","bank", p_logCode, pPrefix,true,1,null,p_values);
	}
	
	/**头部不增加时间，用于输出直联渠道日志
	 * @param p_logCode
	 * @param pPrefix 文件前缀
	 * @param p_values*/
	public void infoNoTimeBank(String p_logCode,String pPrefix, String... p_values){
		appendLog("info", "bank", p_logCode,pPrefix,false,1,null,p_values);
	}
	
	public void error(String p_logCode, String... p_values){
		appendLog("error","", p_logCode,"",true,1,null,p_values);
		FGBiz.limitMsg.error(p_logCode, StringHelper.join("\t", p_values));
	}
	
	public void exception(String p_logCode, Throwable p_ex, String... p_values){
		appendLog("exception","", p_logCode,"",true,1,p_ex,p_values);
		FGBiz.limitMsg.exception(p_logCode, p_ex);
	}
	
	/**加入日志队列
	 * @param p_level 日志等级，如dubug,info,error,exception
	 * @param pDirKey 日志目录键，根据该键值找对应目录
	 * @param pLogCode 日志分类键，日志按该键值创建单独目录，如ABC02、ICBC02
	 * @param pPrifix 日志文件前缀，如果有值，日志文件名将以“pPrifix_”打头，比如1998_
	 * @param p_addTime 是否在日志头部增加时间
	 * @param p_lineCount 尾部添加换行的数量
	 * @param p_ex 要输出异常
	 * @param p_values 要输出日志字符串*/
	public void appendLog(String p_level,String pDirKey, String pLogCode,String pPrefix,boolean p_addTime, int p_lineCount, Throwable p_ex, String... p_values){
		StringBuilder sbMsg = new StringBuilder();
		//yyyy-MM-dd HH:mm:ss SSS
		if(p_addTime){
			sbMsg.append(Format.DateTimeSSSFormat.format(new Date())+"\t"+p_level+"\t");
		}
		
		if(p_values != null){
			for (int i = 0; i < p_values.length; i++) {
	            if (i > 0) {
	            	sbMsg.append("\t");
	            }
	            sbMsg.append(p_values[i]);
	        }
		}
		if(p_ex!=null){
			sbMsg.append("\r\n"+LogHelper.getStackTrace(p_ex));
		}
		
		if (p_lineCount > 0){
            for (int i = 0; i < p_lineCount; i++){
            	sbMsg.append("\r\n");
            }
        }
		//String filePath = pathHelper.getLogFilePath(p_logCode, sbMsg.length());
		//System.out.println("当前输入日志队列["+nowInIdx+"]");
		logQueueList[nowInIdx].add(new String[]{pDirKey, pLogCode,pPrefix, sbMsg.toString()});
    }
	
	/*In1 Out2 3
1 In2 Out3*/
	private int outputLog(){
		//logQueueList[nowInIdx] = new LogQueue();
		int nowOut = (nowInIdx+1)%logQueueList.length;
		LogQueue outQueue = logQueueList[nowOut];
		//System.out.println("当前输出队列["+nowOut+"]");
		int rdCount = outQueue.output(pathHelper);
		nowInIdx = nowOut;
		//System.out.println("当前输入队列设置为["+nowInIdx+"]");
		return rdCount;
	}
	
	private boolean needStop;
	public String stop(){
		needStop = true;
		return "";
	}

	public void run() {
		needStop = false;
		int zeroCount = 0;
		while(true){
			try {
				if(needStop){
					break;
				}
				int rdCount = 0;
				for(int i=0;i<logQueueList.length;i++){
					rdCount = outputLog();
					if(rdCount > 0){
						break;
					}
				}
				if(rdCount == 0){
					zeroCount++;
					if(zeroCount>=10){//大于10次日志为空，则sleep(3000)
						if(zeroCount==Integer.MAX_VALUE){//防止溢出
							zeroCount = 10;
						}
						//System.out.println("sleep(3000)");
						Thread.sleep(3000);
					}else{
						//System.out.println("sleep(1200)");
						Thread.sleep(1200);
					}
				}else if(rdCount >= 300){
					zeroCount = 0;
					//System.out.println("sleep(300)");
					Thread.sleep(300);
				}else{
					zeroCount = 0;
					//System.out.println("sleep(600)");
					Thread.sleep(600);
				}
			} catch (InterruptedException ex) {
				FGBiz.limitMsg.exception("LogTraceException", ex);
			}
			catch (Throwable e) {
				FGBiz.limitMsg.exception("LogTraceThrowable", e);
			}
		}
	}
}
